home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / pctj1086.arc / LOWEGA.MOD < prev    next >
Text File  |  1986-08-15  |  28KB  |  789 lines

  1. IMPLEMENTATION MODULE LowEGA;
  2. (*
  3. Title   : LowEGA
  4.  
  5.           Low level EGA facilities
  6.           Supplies useful workarounds to the Bios and
  7.           extensions thereto such as split screen.
  8. LastEdit: July 14, 1986
  9. Author  : John T. Cockerham, M.D.
  10. System  : LOGITECH MODULA-2/86
  11. *)
  12.                   (* This is a low level module*)
  13.   FROM SYSTEM IMPORT INBYTE, OUTBYTE, OUTWORD, AX, BX, CX, DX, ES,
  14.        ADR, BP, GETREG, SETREG, SWI, ADDRESS, CODE, BYTE, WORD;
  15.   FROM PointLib IMPORT Point, MakePoint;
  16.   FROM Opcodes IMPORT PushBP, PopBP;
  17.   TYPE
  18.     Register =  RECORD CASE BOOLEAN OF TRUE : X : CARDINAL;
  19.                                     | FALSE : L, H : CHAR; END; END;
  20.     ByteADRType = RECORD
  21.             CASE BOOLEAN OF  TRUE : adr : POINTER TO CHAR;
  22.                           | FALSE : off, seg : CARDINAL; END; END;
  23.  
  24.   CONST
  25.             TotalScanLinesEnhanced = 349;
  26.             VIDEO = 10H;
  27.             SetPageBiosCall = 005H;
  28.             SetPaletteCall  = 010H;
  29.             CharacterGeneratorFunction = 011H;
  30.             WriteTTY = 00EH;
  31.             SetCPos = 002H;
  32.             AlphaPageSize = 2048;
  33.             BottomOfScreen = 01FFH;
  34.  
  35.          (* This is the bit layout for Info and Info3 -- EGA
  36.             information bytes found the Bios page *)
  37.             CursorEmulateBit = 0;   MonoAttachedBit = 1;
  38.             WaitForEnableBit = 2;   EGAIsActiveBit  = 3;
  39.             MemoryBit1       = 5;   MemoryBit2      = 6;
  40.             ModeSetClearBit  = 7;
  41.  
  42.             VerticalRetraceBit = 3;
  43.  
  44.          (* These are EGA IO registers *)
  45.      Graph1          = 03CCh; Graph2          = 03CAh;
  46.      Graph12         = 03CEh; MiscOut         = 03C2h;
  47.      Status0         = 03C2h; Sequencer       = 03C4h;
  48.      AttributeCntrl  = 03C0h; GraphData       = 03CFh;
  49.      StatusRegisterOffset = 6;
  50.          (* These are the names of the EGA indices *)
  51.          (* Sequencer controller first *)
  52.      SequenceReset     = 0;     SequenceClockMode = 1;
  53.      SequenceMapMask   = 2;     SequenceCharMap   = 3;
  54.      SequenceMemMode   = 4;
  55.          (* CRT controller registers *)
  56.      CRTHorizTotal    = 00h;     CRTHorizEnd      = 01h;
  57.      CRTHorizBlStart  = 02h;     CRTHorizBlEnd    = 03h;
  58.      CRTHorizRetStart = 04h;     CRTHorizRetEnd   = 05h;
  59.      CRTVertTotal     = 06h;     CRTOvflo         = 07h;
  60.      CRTPreRowScan    = 08h;     CRTMaxScanLine   = 09h;
  61.      CRTCursorStart   = 0Ah;     CRTCursorEnd     = 0Bh;
  62.      CRTStartAddHi    = 0Ch;     CRTStartAddLo    = 0Dh;
  63.      CRTCursLocHi     = 0Eh;     CRTCursLocLo     = 0Fh;
  64.      CRTVertRetSt     = 10h;     CRTLightPenHi    = 10h;
  65.      CRTVertRetEnd    = 11h;     CRTLightPenLo    = 11h;
  66.      CRTVertDisEnd    = 12h;     CRTOffset        = 13h;
  67.      CRTUnderLoc      = 14h;     CRTVertBlSt      = 15h;
  68.      CRTVertBlEnd     = 16h;     CRTModeControl   = 17h;
  69.      CRTLineCompare   = 18h;
  70.         (* Graphics Controller indices *)
  71.      GraphReset       = 00h;     GraphEnable      = 01h;
  72.      GraphColorComp   = 02h;     GraphDataRotate  = 03h;
  73.      GraphReadMapSel  = 04h;     GraphModeReg     = 05h;
  74.      GraphMisc        = 06h;     GraphColorDC     = 07h;
  75.      GraphBitMask     = 08h;
  76.         (* Memory Mapping mode values *)
  77.      A000x128K        = 00h;     A000x64K         = 04h;
  78.      B000x32K         = 08h;     B800x32K         = 0Ch;
  79.      GraphicsModeBit  = 01h;     ChainEvenToOdd   = 02h;
  80.         (* Attribute Controller indices *)
  81.      AttrModeControl  = 10h;     AttrOverscan     = 11h;
  82.      AttrColorPlane   = 12h;     AttrHorizPelPan  = 13h;
  83.      PaletteOn        = 20h;
  84.  
  85.   VAR
  86.      VIDEORAM             : ByteADRType;
  87.      bitmasks             : ARRAY [0..7] OF CARDINAL;
  88.      Cursors              : ARRAY [0..7] OF Point;
  89.      ActivePageOffsets    : ARRAY [0..7] OF CARDINAL;
  90.      i                    : CARDINAL;
  91.      CRTCOverflowRegister : BITSET;
  92.      PelScrollColumn      : INTEGER;
  93.      VerticalScrollRow    : INTEGER;
  94.      SplitScreenLine      : CARDINAL;
  95.      EGA6845              : CARDINAL;
  96.  
  97. (*$S-*)(*$T-*)(*$R-  Turn off Stack Checking for performance
  98.                      and reentrancy reasons *)
  99.   PROCEDURE EGAOutWord(EGAPort, DeviceRegister, Value : CARDINAL);
  100.     (*Output two bytes to the EGA at two successive IO addresses *)
  101.     VAR A : Register;
  102.   BEGIN
  103.     A.L := CHR(DeviceRegister); A.H := CHR(Value);
  104.     OUTWORD(EGAPort, A.X);
  105.   END EGAOutWord;
  106.  
  107.   PROCEDURE WaitForVerticalRetrace;
  108.     (* Wait in a tight loop for vertical retrace *)
  109.     VAR InputStatusRegister1 : BITSET;
  110.   BEGIN
  111.     REPEAT
  112.         INBYTE(EGA6845 + StatusRegisterOffset,InputStatusRegister1);
  113.     UNTIL VerticalRetraceBit IN InputStatusRegister1;
  114.   END WaitForVerticalRetrace;
  115.  
  116.   PROCEDURE WaitForVerticalDisplay;
  117.     (* Wait in a tight loop for vertical display active *)
  118.     VAR InputStatusRegister1 : BITSET;
  119.   BEGIN
  120.     REPEAT
  121.         INBYTE(EGA6845 + StatusRegisterOffset,InputStatusRegister1);
  122.     UNTIL NOT (VerticalRetraceBit IN InputStatusRegister1);
  123.   END WaitForVerticalDisplay;
  124.  
  125.   PROCEDURE SetPageOffset(where : CARDINAL);
  126.     (* Instruct the CRTC where the page starts after retrace *)
  127.     VAR   A : Register;
  128.   BEGIN
  129.     A.X := ActivePageOffset;
  130.     WaitForVerticalRetrace;
  131.     EGAOutWord(EGA6845, CRTStartAddHi,  ORD(A.H));
  132.     EGAOutWord(EGA6845, CRTStartAddLo,  ORD(A.L));
  133.   END SetPageOffset;
  134.  
  135.   PROCEDURE SetActiveFonts(FontA, FontB : CARDINAL);
  136.     (* This routine changes the active character map for
  137.        text modes. It is written as a reentrant procedure *)
  138.     VAR x : CARDINAL;
  139.   BEGIN
  140.     x := FontA * 2 + FontB;
  141.     WaitForVerticalRetrace;
  142.     EGAOutWord(Sequencer, SequenceCharMap, x);
  143.   END SetActiveFonts;
  144.  
  145.   (*$S+*)(*$T+*)(*$R+ Turn run time services back on*)
  146.  
  147.   PROCEDURE InitEGA(EGAMonitor : MonitorType) : BOOLEAN;
  148.     (* This routine sets up the EGA for alpha Mode 3 *)
  149.   BEGIN
  150.     SetUpAlpha;   MemoryInstalled := 0;
  151.     IF MemoryBit2 IN EGABiosParams.InfoAndInfo3
  152.        THEN MemoryInstalled := 2 END;
  153.     IF MemoryBit1 IN EGABiosParams.InfoAndInfo3
  154.        THEN INC(MemoryInstalled) END;
  155.     IF EGAMonitor = Monochrome THEN
  156.       IF MonoAttachedBit IN EGABiosParams.InfoAndInfo3 THEN
  157.         EGA6845 := 03B4H;
  158.       ELSE
  159.         RETURN FALSE;
  160.       END;
  161.     ELSE
  162.       IF NOT (MonoAttachedBit IN EGABiosParams.InfoAndInfo3) THEN
  163.         EGA6845 := 03D4H;
  164.       ELSE
  165.         RETURN FALSE;
  166.       END;
  167.       RETURN TRUE;
  168.     END;
  169.   END InitEGA;
  170.  
  171.   PROCEDURE SetUpAlpha;
  172.     (*This is a non standard set up to the EGA to Alpha
  173.       80X25 on the graphics page (A000).  Assertion that EGA
  174.       is already in mode 3 and EGA is configured with 256K RAM *)
  175.     VAR
  176.       a, b : Register;
  177.   BEGIN
  178.       EGAOutWord(Graph12, GraphMisc,
  179.             A000x64K + ChainEvenToOdd); (* Map to the A000 map *)
  180.       EGAOutWord(EGA6845, CRTOvflo, 01FH);
  181.       CRTCOverflowRegister := {4, 3, 2, 1, 0}
  182.   END SetUpAlpha;
  183.  
  184.   PROCEDURE SetUpHiRes;
  185.     (* This routine changes the EGA operating mode to HiRes color
  186.        graphics. All of these register settings are from the
  187.        boards' documentation  *)
  188.   BEGIN
  189.     WaitForVerticalRetrace;
  190.     EGAOutWord(Sequencer, SequenceMapMask,  00FH);
  191.     EGAOutWord(Sequencer, SequenceMemMode,  006H);
  192.     EGAOutWord(EGA6845, CRTHorizRetStart,  052H);
  193.     EGAOutWord(EGA6845, CRTHorizRetEnd,  000H);
  194.     EGAOutWord(EGA6845, CRTOvflo,  01FH);
  195.     CRTCOverflowRegister := {4, 3, 2, 1, 0};
  196.     ResetVerticalScroll;
  197.     ResetSplitScreen;
  198.     EGAOutWord(EGA6845, CRTMaxScanLine,  000H);
  199.     EGAOutWord(EGA6845, CRTCursorStart,  01FH); (*Turn off cursor*)
  200.     EGAOutWord(EGA6845, CRTCursorEnd,  000H);
  201.     EGAOutWord(EGA6845, CRTVertBlSt,  05FH);
  202.     EGAOutWord(EGA6845, CRTModeControl,  0E3H); (*Byte Mode *)
  203.     EGAOutWord(EGA6845, CRTLineCompare,  0FFH);
  204.     EGAOutWord(Graph12, GraphModeReg,  000H);
  205.     EGAOutWord(Graph12, GraphMisc,  A000x64K + GraphicsModeBit);
  206.     EGAOutWord(Graph12, GraphColorDC,  00FH);
  207.     EGAOutWord(AttributeCntrl, AttrModeControl+PaletteOn, 001H);
  208.     ResetHorizScroll;
  209.     (* We are in writing mode 0 with all maps on this will
  210.        clear out the display buffer *)
  211.     FOR i := 0 TO 65500 DO DisplayBuffer[i] := 0C; END;
  212.   END SetUpHiRes;
  213.  
  214.   (*----------------------------------------------------*)
  215.   (*        Position fiddling procedures                *)
  216.   (*            Warning for these routines:             *)
  217.   (*               Knowledge of exact mode              *)
  218.   (*               specifications including word/byte   *)
  219.   (*               count by 2 etc is essential to using *)
  220.   (*               these routines                       *)
  221.   (*----------------------------------------------------*)
  222.  
  223.   PROCEDURE SetLogicalRowSize(RowSizeInWords : CARDINAL);
  224.     (* This routine sets the offset register of the CRTC. Word/byte
  225.        issues play a role in its setting *)
  226.   BEGIN
  227.     EGAOutWord(EGA6845, CRTOffset, RowSizeInWords);
  228.   END SetLogicalRowSize;
  229.  
  230.   PROCEDURE SetUnderlineLocation(UnderlineScanLine : CARDINAL);
  231.     (* Set the CRTC's scan line for underlining *)
  232.   BEGIN
  233.     EGAOutWord(EGA6845, CRTUnderLoc, UnderlineScanLine);
  234.   END SetUnderlineLocation;
  235.  
  236.   (*----------------------------------------------------*)
  237.   (*      Mode Switching routines between the monitors  *)
  238.   (*      Warning -- Two monitor systems only           *)
  239.   (*                 Bad results can happen if on mono  *)
  240.   (*                    systems only!                   *)
  241.   (*----------------------------------------------------*)
  242.  
  243.   VAR
  244.            EquipFlag     [0:410H]    : BITSET;
  245.  
  246.   PROCEDURE SwitchToMonoBios;
  247.     (* Adjust the Equipment Flag to indicate a Monochrome System *)
  248.   BEGIN
  249.     EquipFlag := EquipFlag + {4, 5};
  250.   END SwitchToMonoBios;
  251.  
  252.   PROCEDURE SwitchToColorBios;
  253.     (* Adjust the Bios Equipment Flag to indicate Color system *)
  254.   BEGIN
  255.     EquipFlag := EquipFlag - {4} + {5};
  256.   END SwitchToColorBios;
  257.  
  258.   PROCEDURE ColorBiosMode() : BOOLEAN;
  259.     (* Return the status of the Flag. False = Monochrome,
  260.        true = Color. *)
  261.   BEGIN
  262.     RETURN (NOT ((5 IN EquipFlag) AND (4 IN EquipFlag)));
  263.   END ColorBiosMode;
  264.  
  265.  
  266. (*------------------------------------------------------*)
  267. (*   Cursor Routines                                    *)
  268. (*------------------------------------------------------*)
  269.  
  270.   PROCEDURE SetCursor(Page : CARDINAL);
  271.     (* Set the Cursor to display for the given page *)
  272.     VAR  Off : Register;
  273.   BEGIN
  274.     Off.X := CursorOffset(Page) DIV 2;
  275.     EGAOutWord(EGA6845, CRTCursLocHi, ORD(Off.H));
  276.     EGAOutWord(EGA6845, CRTCursLocLo, ORD(Off.L));
  277.   END SetCursor;
  278.  
  279.   PROCEDURE CursorOffset(Page : CARDINAL) : CARDINAL;
  280.     (* Calculate cursor offset for CPU mappings: which is doubled
  281.        accouting for the attribute byte *)
  282.   BEGIN
  283.     RETURN ((ActivePageOffsets[Page] +
  284.        CARDINAL(Cursors[Page].y) * ORD(BiosCRTParams.CRTCols) +
  285.        CARDINAL(Cursors[Page].x)) * 2);
  286.   END CursorOffset;
  287.  
  288.   PROCEDURE BumpCursor(Page : CARDINAL);
  289.     (*Increment the cursor in the X direction one unit. If the cursor
  290.       falls off the row, reset to the beginning of the next row. Rows
  291.       wrap around to the start of the screen *)
  292.   BEGIN
  293.     INC(Cursors[Page].x);
  294.     IF Cursors[Page].x >= INTEGER(BiosCRTParams.CRTCols) THEN
  295.       Cursors[Page].x := 0;
  296.       INC(Cursors[Page].y);
  297.       IF ORD(Cursors[Page].y) > ORD(RowsOnScreen) THEN
  298.         Cursors[Page].y := 0;
  299.       END;
  300.     END;
  301.     IF Page = ActivePage THEN SetCursor(Page); END;
  302.   END BumpCursor;
  303.  
  304.   PROCEDURE SetCursorPoint(Page : CARDINAL; p : Point);
  305.     (* Set the cursor to point 'p'. Don't allow it to fall off
  306.        either edge of the display *)
  307.   BEGIN
  308.     IF p.x < INTEGER(BiosCRTParams.CRTCols) THEN
  309.       Cursors[Page].x := p.x;
  310.     ELSE
  311.       Cursors[Page].x := INTEGER(BiosCRTParams.CRTCols) - 1;
  312.     END;
  313.     IF p.y <= INTEGER(ORD(RowsOnScreen)) THEN
  314.       Cursors[Page].y := p.y;
  315.     ELSE
  316.       Cursors[Page].y := ORD(RowsOnScreen);
  317.     END;
  318.     IF Page = ActivePage THEN SetCursor(Page); END;
  319.   END SetCursorPoint;
  320.  
  321.   PROCEDURE GetCursorPoint(VAR p : Point; Page : CARDINAL);
  322.     (* Return the cursor position for the given page *)
  323.   BEGIN
  324.     p := Cursors[Page];
  325.   END GetCursorPoint;
  326.  
  327.  
  328.   (*----------------------------------------------------*)
  329.   (*    Alpha mode write routines                       *)
  330.   (*----------------------------------------------------*)
  331.  
  332.   PROCEDURE Write(Page : CARDINAL; ch : CHAR; color : INTEGER);
  333.     (* Place one character into the display buffer at the
  334.        cursor. The cursor in moved to the next column.
  335.        Color represents the attribute byte *)
  336.     VAR   x : CARDINAL;
  337.   BEGIN
  338.     x := CursorOffset(Page);
  339.     DisplayBuffer[x] := ch;
  340.     DisplayBuffer[x+1] := CHR(color);
  341.     BumpCursor(Page);
  342.   END Write;
  343.  
  344.   PROCEDURE WriteString(Page: CARDINAL; s : ARRAY OF CHAR;
  345.                         c : CARDINAL);
  346.     (* Place a string into the display buffer at the cursor.
  347.        The string is written one character at a time with
  348.        the attribute byte of c *)
  349.     VAR i : CARDINAL;
  350.   BEGIN
  351.     i := 0;
  352.     WHILE i <= HIGH(s) DO
  353.       Write(Page, s[i], c);
  354.       INC(i);
  355.     END;
  356.   END WriteString;
  357.  
  358.   (*----------------------------------------------------*)
  359.   (*    Virtual page manipulation routines              *)
  360.   (*----------------------------------------------------*)
  361.  
  362.   PROCEDURE SetActivePage(page : CARDINAL);
  363.     (* Set the active display page to 'page' resetting
  364.        any scrolling etc. *)
  365.   BEGIN
  366.     ActivePage := page;
  367.     ResetHorizScroll;
  368.     ResetVerticalScroll;
  369.     IF page <= MaxVideoPages THEN
  370.       ActivePageOffset := ActivePageOffsets[page];
  371.       SetPageOffset(ActivePageOffset);
  372.       SetCursor(page);
  373.     END;
  374.   END SetActivePage;
  375.  
  376.   PROCEDURE MakeSecondGraphicsPage;
  377.     (* This routine arbitrarily sets the offset to the
  378.        second hi res graphics page *)
  379.   BEGIN
  380.     ActivePageOffset := 8000H;
  381.     SetPageOffset(ActivePageOffset);
  382.     SetBiosPage(1);
  383.   END MakeSecondGraphicsPage;
  384.  
  385.   PROCEDURE ResetVideoPage;
  386.     (*This routine resets the current video page, and
  387.       get rid of any scrolling and split screens, etc.*)
  388.   BEGIN
  389.     SetActivePage(ActivePage);
  390.     ResetSplitScreen;
  391.   END ResetVideoPage;
  392.  
  393.   (*----------------------------------------------------*)
  394.   (*      Attribute manipulation routines               *)
  395.   (*----------------------------------------------------*)
  396.  
  397.   PROCEDURE SetPalette(Palette, Color : CARDINAL);
  398.     (* This routine sets up the palette RAM in the
  399.        attribute controller with the pattern in Color *)
  400.   BEGIN
  401.     WaitForVerticalRetrace;
  402.     EGAOutWord(AttributeCntrl, Palette, Color);
  403.     EGAOutWord(AttributeCntrl, AttrColorPlane+PaletteOn, 0FH);
  404.   END SetPalette;
  405.  
  406.   PROCEDURE SetOverscan(Color : CARDINAL);
  407.     (* This routine sets up the overscan color for a border
  408.        with the pattern in Color *)
  409.   BEGIN
  410.     WaitForVerticalRetrace;
  411.     EGAOutWord(AttributeCntrl, AttrOverscan, Color);
  412.     EGAOutWord(AttributeCntrl, AttrColorPlane+PaletteOn, 0FH);
  413.   END SetOverscan;
  414.  
  415.   PROCEDURE TurnOnBlinking;
  416.   BEGIN
  417.     EGAOutWord(AttributeCntrl, AttrModeControl+PaletteOn, 09H);
  418.   END TurnOnBlinking;
  419.  
  420.   PROCEDURE TurnOffBlinking;
  421.   BEGIN
  422.     EGAOutWord(AttributeCntrl, AttrModeControl+PaletteOn, 01H);
  423.   END TurnOffBlinking;
  424.  
  425.   (*----------------------------------------------------*)
  426.   (*     Horizontal scrolling routines                  *)
  427.   (*----------------------------------------------------*)
  428.  
  429.   PROCEDURE HorScrollLeft;
  430.     (* Horizontal scrolling left means advancing the page offset
  431.        when falling off the pixel box. The routine is specific
  432.        for 8 pixels per byte  *)
  433.   BEGIN
  434.     INC(PelScrollColumn);
  435.     WaitForVerticalDisplay;
  436.     IF PelScrollColumn > 7 THEN
  437.       PelScrollColumn := 0;
  438.       INC(ActivePageOffset);
  439.       SetPageOffset(ActivePageOffset);  (* Does a Wait already*)
  440.       EGAOutWord(AttributeCntrl, AttrHorizPelPan+PaletteOn,
  441.                  PelScrollColumn);
  442.     ELSE;
  443.       WaitForVerticalRetrace;
  444.       EGAOutWord(AttributeCntrl, AttrHorizPelPan+PaletteOn,
  445.                  PelScrollColumn);
  446.     END;
  447.   END HorScrollLeft;
  448.  
  449.   PROCEDURE HorScrollRight;
  450.   BEGIN
  451.     DEC(PelScrollColumn);
  452.     WaitForVerticalDisplay;
  453.     IF PelScrollColumn < 0 THEN
  454.       PelScrollColumn := 7;
  455.       DEC(ActivePageOffset);
  456.       SetPageOffset(ActivePageOffset);
  457.       EGAOutWord(AttributeCntrl, AttrHorizPelPan+PaletteOn,
  458.                  PelScrollColumn);
  459.     ELSE
  460.       WaitForVerticalRetrace;
  461.       EGAOutWord(AttributeCntrl, AttrHorizPelPan+PaletteOn,
  462.                  PelScrollColumn);
  463.     END;
  464.   END HorScrollRight;
  465.  
  466.   PROCEDURE HorizScroll(pixels : INTEGER);
  467.     VAR i : INTEGER;
  468.   BEGIN
  469.     IF pixels = 0 THEN RETURN; END;
  470.     IF pixels > 0 THEN
  471.       FOR i := 1 TO pixels DO HorScrollLeft; END;
  472.     ELSE
  473.       FOR i := -1 TO pixels BY -1 DO HorScrollRight; END;
  474.     END;
  475.   END HorizScroll;
  476.  
  477.   PROCEDURE ResetHorizScroll;
  478.   BEGIN
  479.     PelScrollColumn := 0;
  480.     WaitForVerticalRetrace;
  481.     EGAOutWord(AttributeCntrl, AttrHorizPelPan+PaletteOn, 0);
  482.   END ResetHorizScroll;
  483.  
  484.      (*-------------------------------------------------*)
  485.      (*         Vertical Scrolling                      *)
  486.      (*      only has meaning in alpha modes            *)
  487.      (*-------------------------------------------------*)
  488.  
  489.   PROCEDURE VerticalScrollUp;
  490.     (* Smooth vertical scroll uses the Preset row scan register
  491.        in the CRTC. When the row is completely scrolled,
  492.        the offset pointer is advanced by one row size *)
  493.   BEGIN
  494.     INC(VerticalScrollRow);  WaitForVerticalDisplay;
  495.     IF VerticalScrollRow >= INTEGER(BytesPerChar) THEN
  496.       ActivePageOffset := ActivePageOffset + BiosCRTParams.CRTCols;
  497.       VerticalScrollRow := 0;
  498.       SetPageOffset(ActivePageOffset);
  499.       EGAOutWord(EGA6845, CRTPreRowScan, VerticalScrollRow);
  500.     ELSE
  501.       WaitForVerticalRetrace;
  502.       EGAOutWord(EGA6845, CRTPreRowScan, VerticalScrollRow);
  503.     END;
  504.   END VerticalScrollUp;
  505.  
  506.   PROCEDURE VerticalScrollDown;
  507.     (* Vertical Scrolling down is the same as up except the row
  508.        changes backward, each character row is brought down a line
  509.        at a time by setting the preset row scan register to the
  510.        high value and decrementing it. *)
  511.   BEGIN
  512.     DEC(VerticalScrollRow);  WaitForVerticalDisplay;
  513.     IF VerticalScrollRow < 0 THEN
  514.       ActivePageOffset := ActivePageOffset - BiosCRTParams.CRTCols;
  515.       VerticalScrollRow := BytesPerChar - 1;
  516.       SetPageOffset(ActivePageOffset);
  517.       EGAOutWord(EGA6845, CRTPreRowScan, VerticalScrollRow);
  518.     ELSE
  519.       WaitForVerticalRetrace;
  520.       EGAOutWord(EGA6845, CRTPreRowScan, VerticalScrollRow);
  521.     END;
  522.   END VerticalScrollDown;
  523.  
  524.   PROCEDURE ResetVerticalScroll;
  525.   BEGIN
  526.     WaitForVerticalRetrace;
  527.     EGAOutWord(EGA6845, CRTPreRowScan,  0);
  528.     VerticalScrollRow := 0;
  529.   END ResetVerticalScroll;
  530.  
  531.  
  532.  
  533.   (*----------------------------------------------------*)
  534.   (*     Split screen routines                          *)
  535.   (*          The split screen starts at offset in the  *)
  536.   (*           display buffer                           *)
  537.   (*----------------------------------------------------*)
  538.  
  539.   PROCEDURE SplitScreenAt(ScanLine : CARDINAL);
  540.     (* Splitting the screen uses the Line Compare Register of
  541.        the CRTC. The overflow for the 9th bit is placed in the
  542.        CRTC'c overflow register. The screen splits when the
  543.        current video scan line equals the designated value
  544.        in those two registers  *)
  545.     VAR Line : Register;
  546.   BEGIN
  547.     Line.X := ScanLine;
  548.     IF Line.H <> 0C THEN
  549.       CRTCOverflowRegister := CRTCOverflowRegister + {4};
  550.     ELSE
  551.       CRTCOverflowRegister := CRTCOverflowRegister - {4}; END;
  552.     WaitForVerticalDisplay;  WaitForVerticalRetrace;
  553.     EGAOutWord(EGA6845, CRTLineCompare, ORD(Line.L));
  554.     EGAOutWord(EGA6845, CRTOvflo,
  555.                CARDINAL(CRTCOverflowRegister));
  556.     SplitScreenLine := ScanLine;
  557.   END SplitScreenAt;
  558.  
  559.   PROCEDURE RollSplitScreenUp(SplitSizeLines : CARDINAL);
  560.     (* Smoothly bring up the split screen with a delay between
  561.        each line as it is brought up.  *)
  562.     VAR Line : CARDINAL;
  563.   BEGIN
  564.     Line := TotalVerticalScanLines - 1;
  565.     WHILE Line > TotalVerticalScanLines - SplitSizeLines DO
  566.       SplitScreenAt(Line);
  567.       DEC(Line);
  568.       WaitForVerticalRetrace;
  569.     END;
  570.   END RollSplitScreenUp;
  571.  
  572.   PROCEDURE RollSplitScreenDown;
  573.     (* This routines smoothly rolls the split screen back down *)
  574.     VAR Line : CARDINAL;
  575.   BEGIN
  576.     Line := SplitScreenLine + 1;
  577.     WHILE Line < TotalVerticalScanLines DO
  578.       SplitScreenAt(Line);
  579.       INC(Line);
  580.       WaitForVerticalRetrace;
  581.     END;
  582.   END RollSplitScreenDown;
  583.  
  584.   PROCEDURE ResetSplitScreen;
  585.     (* This routine pops the split screen back down, no scrolling
  586.        is performed. *)
  587.   BEGIN
  588.     SplitScreenAt(BottomOfScreen);
  589.   END ResetSplitScreen;
  590.  
  591.   (*----------------------------------------------------*)
  592.   (*       Graphics routines                            *)
  593.   (*----------------------------------------------------*)
  594.  
  595.   PROCEDURE FillGraphicsPage(Color : CARDINAL);
  596.      (* Modify to use writing mode 2: Set every bit in bit plane N
  597.         equal to bit N of the data bytes. Useful for rapid flooding
  598.         of the display ram with a particular palette. *)
  599.      VAR x1, y1 : CARDINAL;
  600.   BEGIN
  601.     EGAOutWord(Graph12, GraphModeReg, 2);
  602.     FOR x1 := 0 TO BiosCRTParams.CRTCols - 1 DO
  603.       FOR y1 := 0 TO 349 DO
  604.         DisplayBuffer[ActivePageOffset + x1 +
  605.                       BiosCRTParams.CRTCols * y1] := CHR(Color);
  606.       END;
  607.     END;
  608.     EGAOutWord(Graph12, GraphModeReg, 0)
  609.   END FillGraphicsPage;
  610.  
  611.   PROCEDURE DrawPointTutorial(p : Point; color : CARDINAL);
  612.   (* This procedure demonstrates the method for turing on
  613.      one pixel. A faster version is below with key parts reduced
  614.      to machine level code *)
  615.   (* Turn on a dot at 'p', setting its 'color'. *)
  616.     VAR  rowbyte, bitmask, byteoffset : CARDINAL;
  617.          Temp : CHAR;
  618.   BEGIN
  619.     (* Here compute the address of the pixel byte to change,
  620.        and its bit offset within the byte. *)
  621.     rowbyte := p.x DIV 8;  bitmask := p.x MOD 8;
  622.     bitmask := bitmasks[bitmask];
  623.     byteoffset := CARDINAL(p.y) * BiosCRTParams.CRTCols + rowbyte
  624.                      + ActivePageOffset;
  625.     VIDEORAM.off := byteoffset;
  626.     (*  Select Graphics Bit Mask Register to mask
  627.         out all but the desired pixel *)
  628.     EGAOutWord(Graph12, GraphBitMask, bitmask);
  629.     (*  Select sequencer map mask to enable all four
  630.         maps and latches even if 2 are present *)
  631.     EGAOutWord(Sequencer, SequenceMapMask, 0FH);
  632.     (* Now read the character to latch it in to the 4 EGA plane
  633.        latches. The value read is of no importance *)
  634.     Temp := VIDEORAM.adr^;
  635.     (* Now blank out the all bytes, to clear out the desired
  636.        pixel. Remember the other bits are still latched in, and
  637.        will be preserved during this operation. *)
  638.     VIDEORAM.adr^ := 0c;
  639.     (* Select sequencer Map Mask to enable only writing to those
  640.        bit planes with bits corresponding to the selected palette *)
  641.     EGAOutWord(Sequencer, SequenceMapMask, color);
  642.     (* Now write all bits out in parallel. The sequencer map
  643.        mask and the board latches preserve all pixels except
  644.        that to be set. *)
  645.     VIDEORAM.adr^ := CHR(0FFH);
  646.     (* Normalize the environment, by resetting the masks and
  647.        the data rotation register *)
  648.     EGAOutWord(Sequencer, SequenceMapMask, 0FH);
  649.     EGAOutWord(Graph12, GraphDataRotate, 0);
  650.     EGAOutWord(Graph12, GraphBitMask, 0FFH);
  651.   END DrawPointTutorial;
  652.  
  653. (*$R-*)(*$S-*)(*$T-*)  (*Turn off overhead calls for speed *)
  654.  
  655.   PROCEDURE DrawPoint(p : Point; color : CARDINAL);
  656.   (* Turn on a dot at 'p', with setting color *)
  657.     VAR
  658.       A : Register;
  659.       rowbyte, bitmask, byteoffset : CARDINAL;
  660.   BEGIN
  661.     rowbyte := p.x DIV 8; (* After a divide dx has modulus *)
  662.     GETREG(DX, bitmask);
  663.     bitmask := bitmasks[bitmask];
  664.     byteoffset := CARDINAL(p.y) * BiosCRTParams.CRTCols + rowbyte
  665.                  + ActivePageOffset;
  666.     SETREG(ES, VIDEORAM.seg);    SETREG(BX, byteoffset);
  667.     SETREG(CX, color);           SETREG(AX, bitmask);
  668.     CODE ( 88h, 0c4h, 0b0h, 08h, 0bah, 0ceh, 03h, 0efh, 0b8h, 02h,
  669.           0ffh, 0b2h, 0c4h, 0efh, 26h, 08ah, 2fh, 26h, 0c6h, 07h,
  670.           00h, 88h, 0cch, 0efh, 026h, 0c6h, 07h, 0ffh, 0b4h, 0ffh,
  671.           0efh, 0b2h, 0ceh, 0b8h, 03h, 00h, 0efh, 0b8h, 08h, 0ffh,
  672.           0efh);
  673.   END DrawPoint;
  674.  
  675. (*$R+*)(*$S+*)(*$T+*)
  676.  
  677. (*------------------------------------------------------*)
  678. (*           BIOS Interface Routines                    *)
  679. (*------------------------------------------------------*)
  680.  
  681. PROCEDURE LoadBiosFont(Font : FontType; ResetFlag : BOOLEAN;
  682.                        Block : CARDINAL);
  683.   VAR A : Register;
  684. BEGIN
  685.   A.H := CHR(CharacterGeneratorFunction);
  686.   A.L := CHR(ORD(Font));
  687.   IF ResetFlag THEN A.L := CHR(ORD(A.L) + 011H);
  688.                ELSE A.L := CHR(ORD(A.L) + 01H) END;
  689.   SETREG(AX, A.X);
  690.   SETREG(BX, Block);
  691.   SWI(VIDEO);
  692. END LoadBiosFont;
  693.  
  694. PROCEDURE LoadUserFont(VAR Font : ARRAY OF CHAR; ResetFlag : BOOLEAN;
  695.                        Block, Count, Points : CARDINAL);
  696.   VAR A, B : Register;
  697.       f : ADDRESS;
  698. BEGIN
  699.   f := ADR(Font);
  700.   A.H := CHR(CharacterGeneratorFunction);
  701.   IF ResetFlag THEN A.L := CHR(010H);
  702.                ELSE A.L := CHR(00H) END;
  703.   B.H := CHR(Points);    B.L := CHR(Block);
  704.   SETREG(CX, Count);     SETREG(BX, B.X);
  705.   SETREG(AX, A.X);       CODE(PushBP); (*Save our BP *)
  706.   SETREG(ES, f.SEGMENT); SETREG(DX, f.OFFSET);
  707.   CODE(89H, 0D5H); (* MOV bp, dx ;Set BP to point at font *)
  708.   SETREG(DX, 0);         SWI(VIDEO);
  709.   CODE(PopBP);  (*Restore the BP *)
  710. END LoadUserFont;
  711.  
  712. PROCEDURE GetAlternatePrintScreen;
  713. BEGIN
  714.   SETREG(AX, 01200H);    SETREG(BX, 0020H);
  715.   SWI(VIDEO);
  716. END GetAlternatePrintScreen;
  717.  
  718. PROCEDURE SetBiosPage(Page : CARDINAL);
  719.   VAR A : Register;
  720. BEGIN
  721.   A.H := CHR(SetPageBiosCall); A.L := CHR(Page);
  722.   SETREG(AX, A.X); SWI(VIDEO);
  723. END SetBiosPage;
  724.  
  725. PROCEDURE SetBiosPalette(Palette, Color : CARDINAL);
  726.   VAR A, B : Register;
  727. BEGIN
  728.   A.H := CHR(SetPaletteCall); A.L := 0C;
  729.   B.H := CHR(Color); B.L := CHR(Palette);
  730.   SETREG(BX, B.X); SETREG(AX, A.X);
  731.   SWI(VIDEO);
  732. END SetBiosPalette;
  733.  
  734. PROCEDURE SetModeBios(Mode : CARDINAL);
  735. BEGIN
  736.   SETREG (AX, Mode);
  737.   SWI(VIDEO);
  738. END SetModeBios;
  739.  
  740. PROCEDURE SetBiosCursorPoint(Page : CARDINAL; p : Point);
  741.   VAR A, B, D : Register;
  742. BEGIN
  743.   A.H := CHR(SetCPos);  A.L := 0C;
  744.   B.H := CHR(Page);     B.L := 0C;
  745.   D.H := CHR(p.y);      D.L := CHR(p.x);
  746.   SETREG(DX, D.X);      SETREG(BX, B.X);
  747.   SETREG(AX, A.X);      SWI(VIDEO);
  748. END SetBiosCursorPoint;
  749.  
  750. PROCEDURE WriteBios(c : CHAR; color : CARDINAL);
  751.   VAR A, B : Register;
  752. BEGIN
  753.   A.H := CHR(WriteTTY); A.L := c;
  754.   B.H := 0C;            B.L := CHR(color);
  755.   SETREG(BX, B.X);      SETREG(AX, A.X);
  756.   SWI(VIDEO);
  757. END WriteBios;
  758.  
  759. PROCEDURE WriteBiosString(msg : ARRAY OF CHAR; color : CARDINAL);
  760.     VAR i : CARDINAL;
  761. BEGIN
  762.   i := 0;
  763.   WHILE i <= HIGH(msg) DO
  764.     WriteBios(msg[i], color);
  765.     INC(i);
  766.   END;
  767. END WriteBiosString;
  768.  
  769. PROCEDURE PrintScreen;
  770. BEGIN
  771.   SWI(05H);
  772. END PrintScreen;
  773.  
  774.  
  775. BEGIN
  776.   VIDEORAM.seg := 0a000H;    VIDEORAM.off := 0;
  777.   bitmasks[7] := 1;          bitmasks[6] := 2;
  778.   bitmasks[5] := 4;          bitmasks[4] := 8;
  779.   bitmasks[3] := 16;         bitmasks[2] := 32;
  780.   bitmasks[1] := 64;         bitmasks[0] := 128;
  781.   MakePoint(Cursors[0], 0, 0);
  782.   FOR i := 1 TO MaxVideoPages DO Cursors[i] := Cursors[0]; END;
  783.   FOR i := 0 TO MaxVideoPages DO
  784.        ActivePageOffsets[i] := i * AlphaPageSize; END;
  785.   PelScrollColumn := 0; VerticalScrollRow := 0;
  786.   TotalVerticalScanLines := TotalScanLinesEnhanced;
  787.   ActivePage := 0;
  788. END LowEGA.
  789.